/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package image.edge.zerocross;

import image.processing.ImageProcessor;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.Set;

/**
 *
 * @author tommy
 */
public class ZeroCross {
	private BufferedImage refImage;
	private double threshold;
	
	public ZeroCross(BufferedImage refImage, double threshold) {
		this.refImage = refImage;
		this.threshold = threshold;
	}
	
	
	public Set<Integer[]> findCrossings(Double[] processedImageMagnitudes) {
		Set<Integer[]> crossIndexes = new HashSet<Integer[]> ();
		
		// fills crossIndexes with coords where zero cross occures in image
		// after laplacian operator applied
		rowIteration(crossIndexes, processedImageMagnitudes);
		colIteration(crossIndexes, processedImageMagnitudes);
		
		return crossIndexes;
	}
	
	private void rowIteration(Set<Integer[]> crossIndexes, Double[] processedImageMagnitudes) {
		Double[][] laplacianMagnMatrix;
		double lapMagnitude, lNeighbour, rNeighbour, slope;
		Integer[] edgeCoord;
		
		laplacianMagnMatrix = ImageProcessor.toMatrix(processedImageMagnitudes, refImage.getWidth(), refImage.getHeight());
		
		// does not check crossings if on left or right edge to avoid indexoutofbounds
		for (int y = 0 ; y < refImage.getHeight() ; y++) {
			for (int x = 1 ; x < refImage.getWidth() - 1 ; x++) {
				lapMagnitude = laplacianMagnMatrix[y][x];
				lNeighbour = laplacianMagnMatrix[y][x-1]; // left pixel
				rNeighbour = laplacianMagnMatrix[y][x+1];// right pixel
				if (lapMagnitude == 0) {
					// sign cross of type: - 0 + || + 0 -
					if (lNeighbour * rNeighbour < 0) {
						slope = Math.abs(lNeighbour + rNeighbour);
						//sign change occure, edge at (x,y)
						
						if (slope > threshold) {
							edgeCoord = new Integer[2];
							edgeCoord[0] = x;
							edgeCoord[1] = y;
							crossIndexes.add(edgeCoord);
						}
					}
				} else {
					// sign cross of type: - + || + - between @(x-1,y) - @(x,y)
					if (lapMagnitude * lNeighbour < 0) {
						slope = Math.abs(lapMagnitude + lNeighbour);
						
						if (slope > threshold) {
							edgeCoord = new Integer[2];
							edgeCoord[0] = x-1;
							edgeCoord[1] = y;
							crossIndexes.add(edgeCoord);
						}
					}
					
					// sign cross of type: - + || + - between @(x,y) - @(x+1,y)
					if (lapMagnitude * rNeighbour < 0) {
						slope = Math.abs(lapMagnitude + rNeighbour);
						
						if (slope > threshold) {
							edgeCoord = new Integer[2];
							edgeCoord[0] = x;
							edgeCoord[1] = y;
							crossIndexes.add(edgeCoord);
						}
					}
				}
			}
		}
	}
	
	private void colIteration(Set<Integer[]> crossIndexes, Double[] laplacianMagnitudes) {
		Double[][] laplacianMagnMatrix;
		double lapMagnitude, lNeighbour, rNeighbour, slope;
		Integer[] edgeCoord;
		
		laplacianMagnMatrix = ImageProcessor.toMatrix(laplacianMagnitudes, refImage.getWidth(), refImage.getHeight());
		// does not check crossings if on upper or lower edge to avoid indexoutofbounds
		for (int x = 0 ; x < refImage.getWidth() ; x++) {
			for (int y = 1 ; y < refImage.getHeight() -1 ; y++) {
				lapMagnitude = laplacianMagnMatrix[y][x];
				lNeighbour = laplacianMagnMatrix[y-1][x]; // left pixel (vertical orient)
				rNeighbour = laplacianMagnMatrix[y+1][x]; // right pixel (vertical orient)
				
				if (lapMagnitude == 0) {
					// sign cross of type: - 0 + || + 0 -
					if (lNeighbour * rNeighbour < 0) {
						slope = Math.abs(lNeighbour + rNeighbour);
						//sign change occure, edge at (x,y)
						
						if (slope > threshold) {
							edgeCoord = new Integer[2];
							edgeCoord[0] = x;
							edgeCoord[1] = y;
							crossIndexes.add(edgeCoord);
						}
					}
				} else {
					// sign cross of type: - + || + - between @(x,y-1) - @(x,y)
					if (lapMagnitude * lNeighbour < 0) {
						slope = Math.abs(lapMagnitude + lNeighbour);
						//sign change occure, edge at (x,y)
						
						if (slope > threshold) {
							edgeCoord = new Integer[2];
							edgeCoord[0] = x;
							edgeCoord[1] = y-1;
							crossIndexes.add(edgeCoord);
						}
					}
					
					// sign cross of type: - + || + - between @(x,y) - @(x,y+1)
					if (lapMagnitude * rNeighbour < 0) {
						slope = Math.abs(lapMagnitude + rNeighbour);
						//sign change occure, edge at (x,y)
						
						if (slope > threshold) {
							edgeCoord = new Integer[2];
							edgeCoord[0] = x;
							edgeCoord[1] = y;
							crossIndexes.add(edgeCoord);
						}
					}
				}
			}
		}
	}
}
